package com.chagee.store.operation.server.task;


import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.TimeInterval;
import cn.hutool.core.util.StrUtil;
import com.alibaba.arms.tracing.Span;
import com.alibaba.arms.tracing.Tracer;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.chagee.store.operation.api.enums.StoreWorkOrderStatusEnum;
import com.chagee.store.operation.common.constant.CommonConstant;
import com.chagee.store.operation.common.enums.EmailReceiverTypeEnum;
import com.chagee.store.operation.common.enums.EmailTypeEnum;
import com.chagee.store.operation.server.event.service.WorkOrderBaseService;
import com.chagee.store.operation.server.event.service.WorkOrderReceiverBaseService;
import com.chagee.store.operation.server.feign.SystemApi;
import com.chagee.store.operation.server.feign.request.ReginRequest;
import com.chagee.store.operation.server.feign.response.SystemResponse;
import com.chagee.store.operation.server.feign.vo.ReginDate;
import com.chagee.store.operation.server.model.bo.ExportOrderEmailBO;
import com.chagee.store.operation.server.model.bo.SupplierStatisticsBO;
import com.chagee.store.operation.server.model.bo.WorkOrderDetailBO;
import com.chagee.store.operation.server.service.EmailBizService;
import com.chagee.store.operation.server.service.WorkOrderAcceptanceService;
import com.chagee.store.operation.server.utils.DateUtil;
import com.google.common.collect.Sets;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.handler.annotation.XxlJob;
import com.xxl.job.core.log.XxlJobLogger;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 邮件推送
 *
 * @Author : hk
 * @Date : 2024/12/26
 */
@Component
@Slf4j
public class NotifySupplierMussedOrderJobHandler {

	@Resource
	private WorkOrderBaseService workOrderBaseService;

	@Resource
	private EmailBizService emailBizService;

	@Resource
	private WorkOrderReceiverBaseService workOrderReceiverBaseService;

	@Resource
	private WorkOrderAcceptanceService workOrderAcceptanceService;

	@Value("${supplier.emailStatistics}")
	private String emailStatistics;

	@Resource
	private SystemApi systemApi;

	private final static String city = "{city}：{size} 家";


	/**
	 * 推送未接单,待交接状态工单门店清单  0 0 3 * * ?
	 *
	 * @param param
	 * @return
	 */
	@XxlJob("notifySupplierMussedOrder")
	public ReturnT<String> pushMissedOrderMsg(String param) {
		Span span = Tracer.builder().getSpan();
		TimeInterval timer = cn.hutool.core.date.DateUtil.timer();
		log.info("推送未接单门店清单定时任务开始,traceId :{}", span.getTraceId());
		try {
			List<WorkOrderDetailBO> result = new ArrayList<>();
			long startIndex = 0L;
			while (true) {
				List<WorkOrderDetailBO> workOrderDetailBOS = workOrderBaseService.selectOrders(startIndex);
				if (CollectionUtils.isEmpty(workOrderDetailBOS)) {
					break;
				}
				result.addAll(workOrderDetailBOS);
				startIndex = Math.toIntExact(workOrderDetailBOS.stream().map(WorkOrderDetailBO::getId).max(Comparator.naturalOrder()).orElse(0L));
			}
			log.info("推送邮件未接单门店清单 :{}", JSON.toJSONString(result));

			if (CollectionUtils.isEmpty(result)) {
				return ReturnT.SUCCESS;
			}

			SupplierStatisticsBO supplierStatisticsBO = JSON.parseObject(emailStatistics, new TypeReference<SupplierStatisticsBO>() {
			});
			int boHuiSize = 0;
			int yySySize = 0;
			int shunYaoJiaSize = 0;
			int shlSize = 0;
			Set<Integer> regionCodeList = Sets.newHashSet();
			List<ExportOrderEmailBO> emailBOList = new ArrayList<>();
			for (WorkOrderDetailBO workOrderDetailBO : result) {
				if (StringUtils.isNotBlank(workOrderDetailBO.getSupplierNo())){
					if (supplierStatisticsBO.getBoHui().contains(workOrderDetailBO.getSupplierNo())) {
						boHuiSize++;
					}
					if (supplierStatisticsBO.getYySy().contains(workOrderDetailBO.getSupplierNo())) {
						yySySize++;
					}
					if (supplierStatisticsBO.getShunYaoJia().contains(workOrderDetailBO.getSupplierNo())) {
						shunYaoJiaSize++;
					}
					if (supplierStatisticsBO.getShl().contains(workOrderDetailBO.getSupplierNo())) {
						shlSize++;
					}
					String storeRegion = StringUtils.substringBeforeLast(workOrderDetailBO.getRegion(), CommonConstant.OR_STRING);

					ExportOrderEmailBO exportOrderEmailBO = new ExportOrderEmailBO()
						.setStoreNo(workOrderDetailBO.getStoreCode())
						.setStoreName(workOrderDetailBO.getStoreName())
						.setCompanyName(workOrderDetailBO.getCompanyName())
						.setSupplierName(workOrderDetailBO.getSupplier())
						.setWorkOrderNumber(workOrderDetailBO.getWorkOrderNumber())
						.setCreateTime(DateUtil.format(workOrderDetailBO.getCreateTime(), DateUtil.DEFAULT_DATE_TIME_PATTERN))
						.setDocumentStatus(StoreWorkOrderStatusEnum.getByType(workOrderDetailBO.getDocumentStatus()).getDesc())
						.setSupplierNo(workOrderDetailBO.getSupplierNo())
						.setRegion(storeRegion);
					emailBOList.add(exportOrderEmailBO);

					if (StringUtils.isNotBlank(storeRegion)) {
						String[] regionCode = storeRegion.split(CommonConstant.OR_STRING);
						if (regionCode.length > 0) {
							List<Integer> codeList = Arrays.stream(regionCode).map(Integer::parseInt).collect(Collectors.toList());
							regionCodeList.addAll(codeList);
						}
					}
				}
			}

			Map<String, List<ExportOrderEmailBO>> listMap = emailBOList.stream().filter(s -> StringUtils.isNotBlank(s.getSupplierNo())).collect(Collectors.groupingBy(ExportOrderEmailBO::getSupplierNo));


			Map<String, Object> hashMap = new HashMap<>();
			hashMap.put("date", DateUtil.yesterdayStr(DateUtil.EMAIL_DATE_PATTERN));
			hashMap.put("supplierName", "");

			hashMap.put("totalSize", emailBOList.size());
			hashMap.put("boHuiSize", boHuiSize);
			hashMap.put("yySySize", yySySize);
			hashMap.put("shunYaoJiaSize", shunYaoJiaSize);
			hashMap.put("shlSize", shlSize);

			//List<ExportOrderEmailBO> collect = listMap.entrySet().stream().map(Map.Entry::getValue).flatMap(List::stream).collect(Collectors.toList());

			// 邮件地址
			String receivers = emailBizService.getReceivers(EmailTypeEnum.NOTIFY_SUPPLIER_MISSED_ORDER_OPENING, EmailReceiverTypeEnum.CLIQUE);
			List<String> list = CollectionUtil.toList(receivers.split(","));

			if (CollectionUtil.isNotEmpty(list) && CollectionUtil.isNotEmpty(emailBOList)) {

				//参数
				builderParam(hashMap, emailBOList, regionCodeList);

				byte[] allInputStream = EmailBizService.buildExcelBytes(ExportOrderEmailBO.class, emailBOList, null);
				try {
					emailBizService.sendEmail(EmailTypeEnum.NOTIFY_SUPPLIER_MISSED_ORDER_OPENING, EmailReceiverTypeEnum.CLIQUE, list, hashMap, hashMap, hashMap, allInputStream);
					log.info("集团项目组人员发送邮件通知成功");
				} catch (Exception e) {
					log.error("集团项目组发送邮件失败通知失败:", e);
				}
			}

			for (Map.Entry<String, List<ExportOrderEmailBO>> entry : listMap.entrySet()) {
				hashMap.put("supplierName", entry.getValue().get(0).getSupplierName());

				byte[] inputStream = EmailBizService.buildExcelBytes(ExportOrderEmailBO.class, entry.getValue(), null);
				try {
					sendEmail(entry.getKey(), hashMap, inputStream);
					log.info("供应商{}发送邮件通知成功:", entry.getKey());
				} catch (Exception e) {
					log.error("供应商{}发送邮件失败通知失败:", entry.getKey(), e);
				}
			}

		} catch (Exception e) {
			XxlJobLogger.log("推送未接单门店清单定时任务异常，异常信息:", e);
			log.error("发送邮件门店清单定时任务异常 => param : {} => 异常信息 :", param, e);
		}
		XxlJobLogger.log("发送邮件门店清单定时任务结束，共耗时:{},TraceId:{}", timer.intervalRestart(), span.getTraceId());
		return ReturnT.SUCCESS;
	}


	private void sendEmail(String supplierNo, Map<String, Object> hashMap, byte[] inputStream) {

		Map<String, String> emailReceivers = emailBizService.getEmailReceivers(EmailTypeEnum.NOTIFY_SUPPLIER_MISSED_ORDER_OPENING, EmailReceiverTypeEnum.SUPPLIER);

		String supplierEmails = emailReceivers.get(supplierNo);
		log.info("emails: {}", supplierEmails);
		if (StringUtils.isBlank(supplierEmails)) {
			return;
		}

		List<String> list = CollectionUtil.toList(supplierEmails.split(","));
		emailBizService.sendEmail(EmailTypeEnum.NOTIFY_SUPPLIER_MISSED_ORDER_OPENING, EmailReceiverTypeEnum.SUPPLIER, list, hashMap, hashMap, hashMap, inputStream);
	}

	public void builderParam(Map<String, Object> hashMap, List<ExportOrderEmailBO> orderEmailBOS, Set<Integer> regionCodeList) {

		Map<String, String> regionName = getRegionName(CollectionUtil.newArrayList(regionCodeList));

		Map<String, List<ExportOrderEmailBO>> emailBOMap = orderEmailBOS.stream().filter(s -> StringUtils.isNotBlank(s.getRegion())).collect(Collectors.groupingBy(ExportOrderEmailBO::getRegion));

		StringBuilder builder = new StringBuilder();
		Map<String, Object> paramMap = new HashMap<>();
		for (Map.Entry<String, List<ExportOrderEmailBO>> entry : emailBOMap.entrySet()) {
			StringBuffer cityBuilder = new StringBuffer();
			String storeRegion = entry.getKey();
			String[] regionCode = storeRegion.split(CommonConstant.OR_STRING);
			for (String s : regionCode) {
				if (StringUtils.isNotBlank(s)) {
					cityBuilder.append(regionName.get(s)).append(CommonConstant.NONE_STRING);
				}
			}
			cityBuilder.deleteCharAt(cityBuilder.lastIndexOf(CommonConstant.NONE_STRING));
			paramMap.put("city", cityBuilder);
			paramMap.put("size", entry.getValue().size());
			String format = StrUtil.format(city, paramMap);
			builder.append(format).append("\n");
		}

		hashMap.put("distribution", builder.toString());
	}

	private Map<String, String> getRegionName(List<Integer> cityRegionList) {

		Map<String, String> map = new HashMap<>();
		if (CollectionUtil.isNotEmpty(cityRegionList)) {
			ReginRequest reginRequest = new ReginRequest();
			reginRequest.setCodeList(cityRegionList);
			SystemResponse<List<ReginDate>> systemResponse = null;
			try {
				systemResponse = systemApi.reginNameListQuery(reginRequest);
			} catch (Exception e) {
				log.error("NotifySupplierMussedOrderJobHandler.systemApi.reginNameListQuery error:", e);
			}
			if (Objects.nonNull(systemResponse)) {
				List<ReginDate> data = systemResponse.getData();
				if (CollectionUtil.isNotEmpty(data)) {
					map = data.stream().collect(Collectors.toMap(ReginDate::getCode, ReginDate::getName));
				}
			}
		}
		return map;
	}
}
